﻿#define Print_Log
#define Print_Warn
#define Print_Error

#if UNITY_EDITOR || UNITY_STANDALONE_WIN
//#define PC_PLATFORM
#endif

#if PC_PLATFORM
#else
#define MOBILE_PLATFORM
#endif

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CameraControl : MonoBehaviour {
    public bool IsPc;

    #region zoom
    public float zoomMax = 45f;
    public float zoomMin = 30f;
    public float zoomBounceFactor = 5f;
    public float zoomSpeedFactor = 20f;
    public float zoomBounceSpeedFactor = 1f;
    public float Dis2Fov = 1f;
    public float Scroll2Fov = 1f;

    bool zooming = false;//temp

    float lastFingerDis = 0.0f;//temp
    float curFingerDis = 0.0f;//temp
    float zoomDiff = 0.0f;
    #endregion

    #region move
    public float moveSpeedFactor = 1f;
    public float lerpDisFactor = 0.1f;
    public float lerpSpeedFactor = 1f;
    public float moveEndThreshold = 1f;

    public Vector3 StartPointPos = Vector3.zero;
    public Vector3 CurPointPos = Vector3.zero;

    Vector2 lastScreenPos = Vector3.zero;
    Vector2 StartScreenPos = Vector2.zero;
    Vector2 EndScreenPos = Vector3.zero;

    public bool mousePress = false;
    public bool moveLerp = false;
    #endregion
    
        
    const float maxCastDis = 1000;

    public Camera castRayCam = null;
    Transform cacheTran = null;
    int terrainLayer ;

    public class TouchInfo
    {
        public TouchPhase phase;
        public int count;
    }
    List<TouchInfo> touchInfoLst = new List<TouchInfo>();


    private void Awake()
    {
        terrainLayer = 1 << LayerMask.NameToLayer("terrain");
    }

    // Use this for initialization
    void Start () {
        cacheTran = transform;
        Application.targetFrameRate = 30;
    }

    // Update is called once per frame 
	void Update () {
#if PC_PLATFORM
        if (Input.GetMouseButtonDown(0))
        {
            mousePress = true;
            moveLerp = false;
            StartPointPos = GetMousePoint(GetFingerPos());

        }

        if (Input.GetMouseButtonUp(0))
        {
            mousePress = false;
            moveLerp = true;
            EndScreenPos = GetFingerPos();
            EndScreenPos += (GetFingerPos() - lastScreenPos) * lerpDisFactor;
        }

        if(lastScreenPos != GetFingerPos())
        {
            lastScreenPos = GetFingerPos();
        }

        float scrollValue = Input.GetAxis("Mouse ScrollWheel");
        if (scrollValue != 0f)
        {
            zoomDiff = scrollValue * Scroll2Fov;
            zooming = true;
        }
        else
        {
            zooming = false;
        }
#endif

#if MOBILE_PLATFORM
        if (Input.touchCount == 1)
        {
            Touch touch = Input.GetTouch(0);
            
            if(touchInfoLst.Count == 0)
            {
                TouchInfo info = new TouchInfo();
                info.phase = touch.phase;
                info.count = 1;
                touchInfoLst.Add(info);
            }
            else
            {
                TouchInfo info = touchInfoLst[touchInfoLst.Count - 1];
                if (info.phase == touch.phase)
                {
                    info.count++;
                }
                else
                {
                    TouchInfo temp = new TouchInfo();
                    temp.phase = touch.phase;
                    temp.count = 1;
                    touchInfoLst.Add(temp);
                }
            }
            

            switch (touch.phase)
            {
                case TouchPhase.Began:
                    break;
                case TouchPhase.Moved:
                    break;
                case TouchPhase.Stationary:
                    break;
                case TouchPhase.Ended:
                    break;
                case TouchPhase.Canceled:
                    break;
                default:
                    break;
            }

            if (touch.phase == TouchPhase.Began)
            {
                mousePress = true;
                moveLerp = false;
                StartPointPos = GetMousePoint(GetFingerPos(0));
            }            

            if(touch.phase == TouchPhase.Ended)
            {
                mousePress = false;
                moveLerp = true;
                EndScreenPos = GetFingerPos(0);
                EndScreenPos += (GetFingerPos(0) - lastScreenPos) * lerpDisFactor;
            }
                       
            if (lastScreenPos != GetFingerPos(0))
            {
                lastScreenPos = GetFingerPos(0);
            }
        }
        

        if (Input.touchCount >= 2)
        {
            Touch touch1 = Input.GetTouch(0);
            Touch touch2 = Input.GetTouch(1);

            curFingerDis = Vector3.Distance(GetFingerPos(0), GetFingerPos(1));
            if (lastFingerDis == 0.0f)
            {
                lastFingerDis = curFingerDis;
            }
            else
            {
                float scrollValue = (lastFingerDis - curFingerDis);
                zoomDiff = scrollValue * Dis2Fov;
                zooming = true;

                lastFingerDis = curFingerDis;
            }
            mousePress = false;
            moveLerp = false;

            if (touch1.phase == TouchPhase.Ended)
            {
                mousePress = true;
                moveLerp = false;
                StartPointPos = GetMousePoint(GetFingerPos(1));
            }
            else if (touch2.phase == TouchPhase.Ended)
            {
                mousePress = true;
                moveLerp = false;
                StartPointPos = GetMousePoint(GetFingerPos(0));
            }
        }
        else
        {
            zooming = false;
            lastFingerDis = 0.0f;
        }
#endif
    }
    
    void LateUpdate()
    {
        if (mousePress)
        {
            CurPointPos = GetMousePoint(GetFingerPos());

            if (Vector3.Distance(CurPointPos, StartPointPos) > moveEndThreshold)
            {
                Vector3 diff = StartPointPos - CurPointPos;
                cacheTran.position = Vector3.Lerp(cacheTran.position, cacheTran.position + diff, Time.deltaTime * moveSpeedFactor);
            }
        }

        if (moveLerp)
        {
            CurPointPos = GetMousePoint(EndScreenPos);

            if (Vector3.Distance(CurPointPos, StartPointPos) > moveEndThreshold)
            {
                Vector3 diff = StartPointPos - CurPointPos;
                cacheTran.position = Vector3.Lerp(cacheTran.position, cacheTran.position + diff, Time.deltaTime * lerpSpeedFactor);
            }
            else
            {
                moveLerp = false;
            }
        }
       

        float curFov = castRayCam.fieldOfView;
        if (zooming )
        {
            float targetFov = Mathf.Lerp(curFov, curFov + zoomDiff, Time.deltaTime * zoomSpeedFactor);
            //float targetFov = curFov + zoomDiff;
            targetFov = Mathf.Clamp(targetFov,zoomMin - zoomBounceFactor, zoomMax + zoomBounceFactor);
            castRayCam.fieldOfView = targetFov;
        }
        else 
        {
            if(curFov < zoomMin || curFov > zoomMax)
            {
                float endFov = curFov < zoomMin ? zoomMin : zoomMax;

                float targetFov = Mathf.Lerp(curFov, endFov, Time.deltaTime * zoomBounceSpeedFactor);
                castRayCam.fieldOfView = targetFov;
            }            
        }
    }

    //viewport 
    Vector2 GetFingerPos(int index = 0)
    {
        Vector2 pos = Vector3.zero;
#if PC_PLATFORM
        Vector3 mousePos = Input.mousePosition;
        pos.x = Mathf.InverseLerp(0, Screen.width, mousePos.x);
        pos.y = Mathf.InverseLerp(0, Screen.height, mousePos.y);
        return pos;
#endif
#if MOBILE_PLATFORM
        if(Input.touchCount == 0)
        {
            return Vector2.zero;
        }

        if(Input.touchCount > index)
        {
            Vector3 mousePos = Input.GetTouch(index).position;
            pos.x = Mathf.InverseLerp(0, Screen.width, mousePos.x);
            pos.y = Mathf.InverseLerp(0, Screen.height, mousePos.y);
            return pos;
        }
        else
        {
            return Vector2.zero;
        }
#endif
    }


    Vector3 GetMousePoint(Vector2 point)
    {
        Ray ray = castRayCam.ViewportPointToRay(point);
        RaycastHit hit;
        bool cast = Physics.Raycast(ray, out hit, maxCastDis, terrainLayer);
        if (cast)
        {
            return hit.point;
        }

        return Vector3.zero;
    }

    void PrintLog(string content)
    {
#if Print_Log
        Debug.Log(content);
#endif
    }

    void PrintWarn(string content)
    {
#if Print_Warn
        Debug.LogWarning(content);
#endif
    }

    void PrintError(string content)
    {
#if Print_Error
        Debug.LogError(content);
#endif
    }

    static GUIStyle style = new GUIStyle();

    private void OnGUI()
    {
        style.fontSize = 40;
        for (int i = 0; i < touchInfoLst.Count; i++)
        {
            TouchInfo info = touchInfoLst[i];
            GUI.Label(new Rect(20, i * 50, 400, 50), string.Format("Phase:{0},Count:{1}", info.phase, info.count), style);
        }
    }
}
